// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
 * Generated on: 2020/2/6
 * Function description: adaption related to the PCIe main chip
 */
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/spinlock_types.h>
#include <linux/module.h>
#include <linux/init.h>
#include "include/mach/hw_drv_core.h"
#include "include/mach/pcie_core.h"
#include "include/mach/pcie_msi.h"
// #include "hi_serdes_types.h"

/* setup resource */
static int32_t pcie_controllers_nr;
/* pcie0 & pcie1 sel: */
static uint32_t g_pcie0_sel = pcie_sel_none; /* default controller is pcie0 */
static uint32_t g_pcie1_sel = pcie_sel_none; /* pcie1 controller is not selected */
static uint32_t g_pcie2_sel = pcie_sel_none; /* pcie2 controller is not selected */

/* mem space size */
static uint32_t g_pcie0_mem_space_size = PCIE_MEM_SPACE_SIZE;  /* default mem space size: 10M */
static uint32_t g_pcie1_mem_space_size = PCIE_MEM_SPACE_SIZE;  /* default mem space size: 10M */
static uint32_t g_pcie2_mem_space_size = PCIE_MEM_SPACE_SIZE;  /* default mem space size: 10M */
static uint32_t g_pcie0_base_space_size = PCIE_BASE_ADDR_SIZE; /* default base space size */
static uint32_t g_pcie1_base_space_size = PCIE_BASE_ADDR_SIZE; /* default base space size */
static uint32_t g_pcie2_base_space_size = PCIE_BASE_ADDR_SIZE; /* default base space size */

/* sys controller map address */
static void *__iomem g_sysctrl_base_virt;

/* locks: read lock & write lock. */
static DEFINE_SPINLOCK(rlock);
static DEFINE_SPINLOCK(wlock);

/* pcie operate function hool */
static struct pci_ops g_pcie_ops;
static struct hw_pci g_sd511x_pcie;

/* pci private data: dbi virtual addr */
static void *g_dbi_base_addr[PCIE_INDEX_MAX][1];
static void **g_pci_private_data[PCIE_INDEX_MAX];

int32_t g_init_result;

static struct pcie_reg_op reg_op_list_1156[] = {
	{ 0x11901004, 0x70000000, 0x0 },
	{ 0x1191b410, 0x7,        0x0 },
	{ 0x11914508, 0x1,        0x0 },
	{ 0x1190101c, 0x800,      0x0 },
	{ 0x11901004, 0x70000000, 0x70000000 },
	{ 0x1191b410, 0x7,        0x6 },
	{ 0x11914414, 0x7,        0x2 },
	{ 0x11914500, 0x3,        0x0 },
	{ 0x11914508, 0x1,        0x1 },
	{ 0x1191b410, 0x7,        0x7 },
};

static struct pcie_reg_op reg_op_list_1155[] = {
	{ 0x11901004, 0x70000000, 0x0 },
	{ 0x1191b410, 0x7,        0x0 },
	{ 0x11914508, 0x1,        0x0 },
	{ 0x1190101c, 0x800,      0x0 },
	{ 0x11901004, 0x70000000, 0x70000000 },
	{ 0x1191b410, 0x7,        0x6 },
	{ 0x11914414, 0x7,        0x2 },
	{ 0x11914500, 0x7,        0x0 },
	{ 0x11914504, 0x7,        0x0 },
	{ 0x11914508, 0x1,        0x1 },
	{ 0x1191b410, 0x7,        0x7 },
	{ 0x11900080, 0x3,        0x2 },
};

struct pcie_reg_base_addr g_pcie_reg_base_addr_comm[PCIE_INDEX_MAX] = {
	{
		.dbi_base_addr = DBI_BASE_ADDR,
		.misc_base_addr = MISC_BASE_ADDR,
		.link_status_reg = PCIE_LINK_STAT0_5116,
		.link_2d0_status_reg = PCIE_LINK_STAT1_5116,
		.mem_base_addr = PCIE0_BASE_ADDR_PHYS,
		.cfg_base_addr = PCIE0_MEMIO_BASE,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE0_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE_MSI_INTERURRPT_NUM_BASE,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	}, {
		.dbi_base_addr = DBI_BASE_ADDR + PCIE1_BASE_REG_OFFSET,
		.misc_base_addr = MISC_BASE_ADDR + PCIE1_BASE_REG_OFFSET,
		.link_status_reg = PCIE_LINK_STAT0_5116,
		.link_2d0_status_reg = PCIE_LINK_STAT1_5116,
		.mem_base_addr = PCIE1_BASE_ADDR_PHYS,
		.cfg_base_addr = PCIE1_MEMIO_BASE,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE1_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE_MSI_INTERURRPT_NUM_BASE + 1,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	},
};

struct pcie_reg_base_addr g_pcie_reg_base_addr_lsw[PCIE_INDEX_MAX] = {
	{
		.dbi_base_addr = DBI_BASE_ADDR,
		.misc_base_addr = MISC_BASE_ADDR,
		.link_status_reg = PCIE_LINK_STAT0_5116,
		.link_2d0_status_reg = PCIE_LINK_STAT1_5116,
		.mem_base_addr = PCIE0_BASE_ADDR_PHYS,
		.cfg_base_addr = PCIE0_MEMIO_BASE,
		.mem_base_size = PCIE_MEM_SPACE_SIZE_LSW,
		.cfg_base_size = PCIE0_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE_MSI_INTERURRPT_NUM_BASE,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	}, {
		.dbi_base_addr = DBI_BASE_ADDR + PCIE1_BASE_REG_OFFSET,
		.misc_base_addr = MISC_BASE_ADDR + PCIE1_BASE_REG_OFFSET,
		.link_status_reg = PCIE_LINK_STAT0_5116,
		.link_2d0_status_reg = PCIE_LINK_STAT1_5116,
		.mem_base_addr = PCIE1_BASE_ADDR_PHYS,
		.cfg_base_addr = PCIE1_MEMIO_BASE,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE1_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE_MSI_INTERURRPT_NUM_BASE + 1,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	},
};

struct pcie_reg_base_addr g_pcie_reg_base_addr_5182t[PCIE_INDEX_MAX] = {
	{
		.dbi_base_addr = DBI_BASE_ADDR_5182T,
		.misc_base_addr = MISC_BASE_ADDR_5182T,
		.link_status_reg = PCIE_LINK_STAT0_5182T,
		.link_2d0_status_reg = PCIE_LINK_STAT0_5182T,
		.mem_base_addr = PCIE0_BASE_ADDR_PHYS_5182T,
		.cfg_base_addr = PCIE0_MEMIO_BASE_5182T,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE0_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE0_MSI_INTERURRPT_NUM_5182T,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	}, {
		.dbi_base_addr = DBI_BASE_ADDR_5182T + PCIE1_BASE_REG_OFFSET_5182T,
		.misc_base_addr = MISC_BASE_ADDR_5182T + PCIE1_BASE_REG_OFFSET_5182T,
		.link_status_reg = PCIE_LINK_STAT0_5182T,
		.link_2d0_status_reg = PCIE_LINK_STAT0_5182T,
		.mem_base_addr = PCIE1_BASE_ADDR_PHYS_5182T,
		.cfg_base_addr = PCIE1_MEMIO_BASE_5182T,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE1_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE1_MSI_INTERURRPT_NUM_5182T,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	}, {
		.dbi_base_addr = DBI_BASE_ADDR_5182T + PCIE2_BASE_REG_OFFSET_5182T,
		.misc_base_addr = MISC_BASE_ADDR_5182T + PCIE2_BASE_REG_OFFSET_5182T,
		.link_status_reg = PCIE_LINK_STAT0_5182T,
		.link_2d0_status_reg = PCIE_LINK_STAT0_5182T,
		.mem_base_addr = PCIE2_BASE_ADDR_PHYS_5182T,
		.cfg_base_addr = PCIE2_MEMIO_BASE_5182T,
		.mem_base_size = PCIE_MEM_SPACE_SIZE,
		.cfg_base_size = PCIE2_BASE_CFG_SIZE,
		.pcie_msi_irq_num = PCIE2_MSI_INTERURRPT_NUM_5182T,
		.reg_op_list_num = 0,
		.reg_op_list = NULL,
	},
};

struct pcie_reg_base_addr g_pcie_reg_base_addr_1156[PCIE_INDEX_MAX] = {
	{
		.dbi_base_addr = PCIE_FST_N_DBI_BASE_1156,
		.misc_base_addr = PCIE_FST_N_MISC_BASE_1156,
		.link_status_reg = PCIE_LINK_STAT0_5182T,
		.link_2d0_status_reg = PCIE_LINK_STAT0_5182T,
		.mem_base_addr = PCIE_FST_N_MEM_BASE_1156,
		.cfg_base_addr = PCIE_FST_N_CFG_BASE_1156,
		.mem_base_size = PCIE_MEM_SPACE_SIZE + PCIE_IO_SPACE_SIZE,
		.cfg_base_size = PCIE_CFG_SPACE_SIZE_1156,
		.pcie_msi_irq_num = PCIE0_MSI_INTERURRPT_NUM_1156,
		.reg_op_list_num = ARRAY_SIZE(reg_op_list_1156),
		.reg_op_list = reg_op_list_1156,
	},
};

struct pcie_reg_base_addr g_pcie_reg_base_addr_1155[PCIE_INDEX_MAX] = {
	{
		.dbi_base_addr = PCIE_FST_N_DBI_BASE_1156,
		.misc_base_addr = PCIE_FST_N_MISC_BASE_1156,
		.link_status_reg = PCIE_LINK_STAT0_5182T,
		.link_2d0_status_reg = PCIE_LINK_STAT0_5182T,
		.mem_base_addr = PCIE_FST_N_MEM_BASE_1156,
		.cfg_base_addr = PCIE_FST_N_CFG_BASE_1156,
		.mem_base_size = PCIE_MEM_SPACE_SIZE + PCIE_IO_SPACE_SIZE,
		.cfg_base_size = PCIE_CFG_SPACE_SIZE_1156,
		.pcie_msi_irq_num = PCIE0_MSI_INTERURRPT_NUM_1156,
		.reg_op_list_num = ARRAY_SIZE(reg_op_list_1155),
		.reg_op_list = reg_op_list_1155,
	},
};

struct pcie_reg_base_addr *g_pcie_reg_base_addr = g_pcie_reg_base_addr_comm;

struct pcie_iatu g_pcie0_iatu_table_1152[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU0_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_CFG_REGION0_BASE,                /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_CFG_REGION0_LIMIT,                /* limit */
		.ltar = PCIE0_CFG_REGION0_TAR,                 /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_1,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU1_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_MEM_REGION1_BASE,                /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_MEM_REGION1_LIMIT,                /* limit */
		.ltar = PCIE0_MEM_REGION1_BASE,                /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_2,                           /* view index */
		.region_ctrl_1 = PCIE0_IATU2_REGION_CTRL_REG1_1152, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,        /* ctrl 2 */
		.lbar = PCIE0_MEM_REGION2_BASE,                     /* base lower */
		.ubar = 0x0,                                        /* base upper */
		.lar = PCIE0_MEM_REGION2_LIMIT,                     /* limit */
		.ltar = PCIE0_MEM_REGION2_TAR_BASE,                 /* target lower */
		.utar = 0x0,                                        /* target upper */
	},
};

struct pcie_iatu g_pcie1_iatu_table_1152[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE1_IATU0_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE1_CFG_REGION0_BASE,                /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE1_CFG_REGION0_LIMIT,                /* limit */
		.ltar = PCIE1_CFG_REGION0_TAR,                 /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion, peripheral configuration space */
		.viewport = IATU_INDEX_1,                           /* view index */
		.region_ctrl_1 = PCIE1_IATU1_REGION_CTRL_REG1_1152, /* ctrl 1 io 64k */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,        /* ctrl 2 */
		.lbar = PCIE1_MEM_REGION1_BASE,                     /* base lower */
		.ubar = 0x0,                                        /* base upper */
		.lar = PCIE1_MEM_REGION1_LIMIT,                     /* limit */
		.ltar = PCIE1_MEM_REGION1_BASE,                     /* target lower */
		.utar = 0x0,                                        /* target upper */
	}, {
		/* init itau reg for cfg opeartion, io opeartion, peripheral internal registers */
		.viewport = IATU_INDEX_2,                      /* view index */
		.region_ctrl_1 = PCIE1_IATU2_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE1_MEM_REGION2_BASE,                /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE1_MEM_REGION2_LIMIT,                /* limit */
		.ltar = PCIE1_MEM_REGION2_TAR_BASE,            /* target lower */
		.utar = 0x0,                                   /* target upper */
	},
};

struct pcie_iatu g_pcie0_iatu_table_extlsw_type2125[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU0_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE0_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_IATU0_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU0_LIMITE_REG,                 /* limit */
		.ltar = PCIE0_IATU0_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_1,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU1_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_IATU1_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU_EXTLSW_LIMIT_MEM_ONE,        /* limit */
		.ltar = PCIE0_IATU1_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_2,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU2_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE0_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_IATU2_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU2_LIMITE_REG,                 /* limit */
		.ltar = PCIE0_IATU2_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_3,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU1_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_IATU2_EXTLSW_LOWER_BASE_REG,     /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU_EXTLSW_LIMIT_MEM_TWO,        /* limit */
		.ltar = PCIE1_IATU3_EXTLSW_LOWER_TARGET_REG,   /* target lower */
		.utar = 0x0,                                   /* target upper */
	},
};

struct pcie_iatu g_pcie0_iatu_table_common[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU0_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE0_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_IATU0_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU0_LIMITE_REG,                 /* limit */
		.ltar = PCIE0_IATU0_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_1,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU1_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_IATU1_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU1_LIMITE_REG,                 /* limit */
		.ltar = PCIE0_IATU1_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_2,                      /* view index */
		.region_ctrl_1 = PCIE0_IATU2_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE0_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_IATU2_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_IATU2_LIMITE_REG,                 /* limit */
		.ltar = PCIE0_IATU2_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	},
};
struct pcie_iatu g_pcie1_iatu_table_common[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE1_IATU0_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE1_IATU0_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE1_IATU0_LIMITE_REG,                 /* limit */
		.ltar = PCIE1_IATU0_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion , peripheral configuration space */
		.viewport = IATU_INDEX_1,                      /* view index */
		.region_ctrl_1 = PCIE1_IATU1_REGION_CTRL_REG1, /* ctrl 1 io 64k */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE1_IATU1_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE1_IATU1_LIMITE_REG,                 /* limit */
		.ltar = PCIE1_IATU1_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion, io operation, peripheral internal registers */
		.viewport = IATU_INDEX_2,                      /* view index */
		.region_ctrl_1 = PCIE1_IATU2_REGION_CTRL_REG1, /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE1_IATU2_LOWER_BASE_REG,            /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE1_IATU2_LIMITE_REG,                 /* limit */
		.ltar = PCIE1_IATU2_LOWER_TARGET_REG,          /* target lower */
		.utar = 0x0,                                   /* target upper */
	},
};

struct pcie_iatu g_pcie0_iatu_table_5182t[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                      /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_CFG0,          /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,   /* ctrl 2 */
		.lbar = PCIE0_CFG_REGION0_BASE_5182T,          /* base lower */
		.ubar = 0x0,                                   /* base upper */
		.lar = PCIE0_CFG_REGION0_LIMIT_5182T,          /* limit */
		.ltar = PCIE0_IATU0_LOWER_TARGET_REG_5182T,    /* target lower */
		.utar = 0x0,                                   /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_1,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_MEM_REGION1_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE0_MEM_REGION1_LIMIT_5182T,         /* limit */
		.ltar = PCIE0_IATU1_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	}, {
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_2,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE0_MEM_REGION2_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE0_MEM_REGION2_LIMIT_5182T,         /* limit */
		.ltar = PCIE0_IATU2_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	},
};

struct pcie_iatu g_pcie1_iatu_table_5182t[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_CFG0,         /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE1_CFG_REGION0_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE1_CFG_REGION0_LIMIT_5182T,         /* limit */
		.ltar = PCIE1_IATU0_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	}, {
		/* init itau reg for cfg opeartion , peripheral configuration space */
		.viewport = IATU_INDEX_1,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 io 64k */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE1_MEM_REGION1_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE1_MEM_REGION1_LIMIT_5182T,         /* limit */
		.ltar = PCIE1_IATU1_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	}, {
		/* init itau reg for cfg opeartion, io operation, peripheral internal registers */
		.viewport = IATU_INDEX_2,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE1_MEM_REGION2_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE1_MEM_REGION2_LIMIT_5182T,         /* limit */
		.ltar = PCIE1_IATU2_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	},
};

struct pcie_iatu g_pcie2_iatu_table_5182t[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_CFG0,         /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE2_CFG_REGION0_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE2_CFG_REGION0_LIMIT_5182T,         /* limit */
		.ltar = PCIE2_IATU0_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	}, {
		/* init itau reg for cfg opeartion , peripheral configuration space */
		.viewport = IATU_INDEX_1,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 io 64k */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE2_MEM_REGION1_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE2_MEM_REGION1_LIMIT_5182T,         /* limit */
		.ltar = PCIE2_IATU1_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	}, {
		/* init itau reg for cfg opeartion, io operation, peripheral internal registers */
		.viewport = IATU_INDEX_2,                     /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,          /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,  /* ctrl 2 */
		.lbar = PCIE2_MEM_REGION2_BASE_5182T,         /* base lower */
		.ubar = 0x0,                                  /* base upper */
		.lar = PCIE2_MEM_REGION2_LIMIT_5182T,         /* limit */
		.ltar = PCIE2_IATU2_LOWER_TARGET_REG_5182T,   /* target lower */
		.utar = 0x0,                                  /* target upper */
	},
};

struct pcie_iatu g_pcie0_iatu_table_1156[] = {
	{
		/* init itau reg for cfg opeartion */
		.viewport = IATU_INDEX_0,                       /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_CFG0,           /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,    /* ctrl 2 */
		.lbar = PCIE_FST_N_CFG_BASE_1156,               /* base lower */
		.ubar = 0x0,                                    /* base upper */
		.lar = PCIE_FST_N_CFG_LIMIT_1156,               /* limit */
		.ltar = PCIE_FST_N_CFG_LOWER_1156,              /* target lower */
		.utar = 0x0,                                    /* target upper */
	}, {
		/* init itau reg for cfg opeartion , peripheral configuration space */
		.viewport = IATU_INDEX_1,                       /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_IO,             /* ctrl 1 io 64k */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,    /* ctrl 2 */
		.lbar = PCIE_FST_N_IO_BASE_1156,                /* base lower */
		.ubar = 0x0,                                    /* base upper */
		.lar = PCIE_FST_N_IO_LIMIT_1156,                /* limit */
		.ltar = PCIE_FST_N_IO_BASE_1156,                /* target lower */
		.utar = 0x0,                                    /* target upper */
	}, {
		/* init itau reg for cfg opeartion, io operation, peripheral internal registers */
		.viewport = IATU_INDEX_2,                       /* view index */
		.region_ctrl_1 = PCIE_IATU_TYPE_MEM,            /* ctrl 1 */
		.region_ctrl_2 = PCIE_IATU_REGION_CTRL_REG2,    /* ctrl 2 */
		.lbar = PCIE_FST_N_MEM_BASE_1156,               /* base lower */
		.ubar = 0x0,                                    /* base upper */
		.lar = PCIE_FST_N_MEM_LIMIT_1156,               /* limit */
		.ltar = PCIE_FST_N_MEM_BASE_1156,               /* target lower */
		.utar = 0x0,                                    /* target upper */
	},
};

static struct resource g_pcie0_mem_space = {
	.name = "PCIE0 memory space",
	.start = PCIE0_BASE_ADDR_PHYS,
	.end = 0,
	.flags = IORESOURCE_MEM,
};

static struct resource g_pcie0_io_space = {
	.name = "PCIE0 io space",
	.start = 0,
	.end = 0,
	.flags = IORESOURCE_IO,
};

static struct resource g_pcie1_mem_space = {
	.name = "PCIE1 memory space",
	.start = PCIE1_BASE_ADDR_PHYS,
	.end = 0,
	.flags = IORESOURCE_MEM,
};

static struct resource g_pcie1_io_space = {
	.name = "PCIE1 io space",
	.start = 0,
	.end = 0,
	.flags = IORESOURCE_IO,
};

static struct resource g_pcie2_mem_space = {
	.name = "PCIE2 memory space",
	.start = PCIE2_BASE_ADDR_PHYS_5182T,
	.end = 0,
	.flags = IORESOURCE_MEM,
};

static struct resource g_pcie2_io_space = {
	.name = "PCIE2 io space",
	.start = 0,
	.end = 0,
	.flags = IORESOURCE_IO,
};

module_param(g_pcie0_sel, uint, PCIE_PARA_RIGHT);
module_param(g_pcie1_sel, uint, PCIE_PARA_RIGHT);
module_param(g_pcie2_sel, uint, PCIE_PARA_RIGHT);

static struct platform_device *g_plat_dev[PCIE_INDEX_MAX];
static uint32_t g_dev_num;

static const struct of_device_id g_pcie_match[] = {
	{ .compatible = "qcom,pcie-ipqxx" },
	{ }
};

static int pcie_plat_probe(struct platform_device *pdev)
{
	if (g_dev_num >= PCIE_INDEX_MAX)
		return 0;

	g_plat_dev[g_dev_num] = pdev;
	g_dev_num++;
	return 0;
}

static int pcie_plat_remove(struct platform_device *pdev)
{
	g_dev_num = 0;
	return 0;
}

static struct platform_driver pcie_driver = {
	.probe = pcie_plat_probe,
	.remove = pcie_plat_remove,
	.driver = {
		.name = "pcie",
		.of_match_table = g_pcie_match,
	},
};

#if KER_F_DESC("internal function")

struct pcie_info *bus_to_info(int32_t busnr)
{
	struct pcie_info *pcie_ctrl;
	int32_t i = pcie_controllers_nr - 1;

	pcie_ctrl = NULL;
	pcie_get_ctrl_info(&pcie_ctrl);
	for (; i >= 0; i--) {
		if ((pcie_ctrl[i].controller != PCIE_CTRL_TYPE_NONE) &&
			(pcie_ctrl[i].root_bus_nr <= busnr) &&
			(pcie_ctrl[i].root_bus_nr != -1))
			return &pcie_ctrl[i];
	}
	return NULL;
}

static int32_t to_pcie_address(struct pci_bus *bus, uint32_t devfn, int32_t where, uint32_t *addr)
{
	struct pcie_info *info;

	info = bus_to_info(bus->number);
	if (info == NULL) {
		pr_info("to pcie address fail controller %d !\n", bus->number);
		return -1;
	}

	*addr = info->conf_base_addr |
			PCIE_CFG_BUS(bus->number) |
			PCIE_CFG_DEV(devfn) |
			PCIE_CFG_REG(where);
	return 0;
}

static int32_t pcie_trans_read_data(int32_t where, int32_t size, int32_t val, int32_t *data)
{
	if (size == PCIE_DATA_SIZE_1)
		*data = PCIE_DATA_SIZE_1_GET(val, where);
	else if (size == PCIE_DATA_SIZE_2)
		*data = PCIE_DATA_SIZE_2_GET(val, where);
	else if (size == PCIE_DATA_SIZE_4)
		*data = val;
	else
		return -1;

	return 0;
}

static int32_t pcie_trans_write_data(int32_t where, int32_t size, int32_t val, int32_t *data)
{
	if (size == PCIE_DATA_SIZE_1) {
		*data &= PCIE_DATA_SIZE_1_CLEAR(where);
		*data |= PCIE_DATA_SET(val, where);
	} else if (size == PCIE_DATA_SIZE_2) {
		*data &= PCIE_DATA_SIZE_2_CLEAR(where);
		*data |= PCIE_DATA_SET(val, where);
	} else if (size == PCIE_DATA_SIZE_4) {
		*data = val;
	} else {
		return -1;
	}

	return 0;
}

int32_t pcie_is_5115_chip(bool *is_old_soc)
{
	uint32_t chip_id;

	/* get soc id */
	chip_id = pcie_get_chip_id();
	if (chip_id == HW_CHIP_ID_MPW_E) {
		pr_info("[pcie]chip type 0x%x is not know!\n", chip_id);
		return -EIO;
	}

	if ((chip_id == HW_CHIP_ID_5115H_E) ||
		(chip_id == HW_CHIP_ID_5115T_E) ||
		(chip_id == HW_CHIP_ID_5610T_E))
		*is_old_soc = true;
	else
		*is_old_soc = false;

	return 0;
}

static int32_t pcie_check_link_status(struct pcie_info *info)
{
	int32_t val;
	int32_t ret;
	uint32_t chipid;
	int32_t pcie_stat_reg_offset;
	bool is_old_soc;

	void *__iomem pcie_misc_base = NULL;

	pcie_stat_reg_offset = 0;
	is_old_soc = false;
	ret = pcie_is_5115_chip(&is_old_soc);
	if (ret != 0)
		return ret;

	pcie_stat_reg_offset = PCIE_LINK_STAT0_5116;
	chipid = pcie_get_chip_id();
	if (chipid == HAL_CHIP_ID_5182T)  // 5182T is not an old soc
		pcie_stat_reg_offset = PCIE_LINK_STAT0_5182T;

	if (is_old_soc == true)
		pcie_stat_reg_offset = (info->controller == PCIE_CTRL_TYPE_0) ?
			PCIE0_LINK_STAT_5115 : PCIE1_LINK_STAT_5115;

	pcie_get_misc_base_virt(info->controller, &pcie_misc_base);
	val = readl(pcie_misc_base + pcie_stat_reg_offset);
	info->state = val;
	return (val & (1 << PCIEX_LINK_UP)) ? true : false;
}

static int32_t pcie_read_from_device(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t *value)
{
	int32_t ret;
	uint32_t val;
	uint32_t addr;
	unsigned long flag;
	int32_t i;
	struct pcie_info *info = bus_to_info(bus->number);

	for (i = 0; i < PCIE_LINK_CHECK_TIMES; i++) {
		if (pcie_check_link_status(info) == true)
			break;
		udelay(PCIE_UDELAY_1000);
	}

	if (i >= PCIE_LINK_CHECK_TIMES) {
		pr_info("pcie%d not link up!\n",
			(info->controller == PCIE_CTRL_TYPE_0) ? 0 : 1);
		return -1;
	}

	flag = 0;
	spin_lock_irqsave(&rlock, flag);
	/* read device is allways type1 */
	ret = to_pcie_address(bus, devfn, where, &addr);
	if (ret != 0) {
		spin_unlock_irqrestore(&rlock, flag);
		return -1;
	}

	val = readl((void *)addr);
	/* if got data is dword align, and val got from offset 0,
	 * i need to calculate which byte is wanted
	 */
	if (pcie_trans_read_data(where, size, val, value)) {
		pr_info("Unknown size(%d) for read ops\n", size);
		spin_unlock_irqrestore(&rlock, flag);
		return -1;
	}

	spin_unlock_irqrestore(&rlock, flag);

	return PCIBIOS_SUCCESSFUL;
}

static int32_t pcie_read_from_dbi(struct pcie_info *info,
	uint32_t devfn, int32_t where, int32_t size, uint32_t *value)
{
	uint32_t val;
	unsigned long flag = 0;

	/* for host-side config space read, ignore device func nr. */
	if (devfn > 0)
		return -EIO;

	spin_lock_irqsave(&rlock, flag);

	val = (uint32_t)readl((void *)(info->conf_base_addr + (where & (~PCIE_DBI_WHERE_MASK))));
	if (pcie_trans_read_data(where, size, val, value)) {
		pr_info("Pcie Unknown size for config read operation!\n");
		spin_unlock_irqrestore(&rlock, flag);
		return -1;
	}

	spin_unlock_irqrestore(&rlock, flag);

	return PCIBIOS_SUCCESSFUL;
}

static int32_t pcie_read_conf(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t *value)
{
	int32_t ret;
	struct pcie_info *info = bus_to_info(bus->number);

	if (unlikely(info == NULL)) {
		pr_info("pcie read conf fail!\n");
		return -EIO;
	}

	if (bus->number == info->root_bus_nr)
		return pcie_read_from_dbi(info, devfn, where, size, value);

	ret = pcie_read_from_device(bus, devfn, where, size, value);
	if (ret != PCIBIOS_SUCCESSFUL)
		pr_info("<%s:%d> %s failed\n", __FILE__, __LINE__, __func__);
	return ret;
}

static int32_t pcie_multifunc_read_from_dbi(struct pcie_info *info,
	uint32_t devfn, int32_t where, int32_t size, uint32_t *value)
{
	uint32_t val;
	uint32_t cfg_shift_addr;
	unsigned long flag = 0;

	/* domain:bus:dev(slot):fn, latter 2 form a devfn. 1 bus only supports 1 dev for now */
	if (PCI_SLOT(devfn) > 0)
		return -EIO;

	spin_lock_irqsave(&rlock, flag);

	cfg_shift_addr = PCIE_CFG_BUS(info->root_bus_nr) |
		PCIE_CFG_DEV(devfn) | PCIE_CFG_REG(where);
	val = (uint32_t)readl((void *)(info->conf_base_addr + cfg_shift_addr));
	if (pcie_trans_read_data(where, size, val, value)) {
		pr_info("Pcie Unknown size for config read operation!\n");
		spin_unlock_irqrestore(&rlock, flag);
		return -1;
	}

	spin_unlock_irqrestore(&rlock, flag);

	return PCIBIOS_SUCCESSFUL;
}

static int32_t pcie_multifunc_read_conf(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t *value)
{
	int32_t ret;
	struct pcie_info *info = bus_to_info(bus->number);

	if (unlikely(info == NULL)) {
		pr_info("pcie read conf fail!\n");
		return -EIO;
	}

	if (bus->number == info->root_bus_nr)
		return pcie_multifunc_read_from_dbi(info, devfn, where, size, value);

	ret = pcie_read_from_device(bus, devfn, where, size, value);
	if (ret != PCIBIOS_SUCCESSFUL)
		pr_info("<%s:%d> %s failed\n", __FILE__, __LINE__, __func__);
	return ret;
}

static int32_t pcie_write_to_device(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t value)
{
	int32_t ret;
	uint32_t addr;
	uint32_t org;
	uint32_t i;
	unsigned long flag;
	struct pcie_info *info = bus_to_info(bus->number);

	for (i = 0; i < PCIE_LINK_CHECK_TIMES; i++) {
		if (pcie_check_link_status(info))
			break;
		udelay(PCIE_UDELAY_1000);
	}

	if (i >= PCIE_LINK_CHECK_TIMES) {
		pr_info("pcie%d not link up!\n", (info->controller == PCIE_CTRL_TYPE_0) ? 0 : 1);
		return -1;
	}

	spin_lock_irqsave(&wlock, flag);
	if (pcie_read_from_device(bus, devfn, where, PCIE_DATA_SIZE_4, &org)) {
		pr_info("Cannot read from dbi! 0x%x:0x%x:0x%x!\n", 0, devfn, where);
		ret = -EIO;
		goto out;
	}

	ret = to_pcie_address(bus, devfn, where, &addr);
	if (ret != 0) {
		ret = -EIO;
		goto out;
	}

	if (pcie_trans_write_data(where, size, value, &org)) {
		pr_info("Unknown size(%d) for read ops\n", size);
		ret = -1;
		goto out;
	}
	writel(org, (void *)addr);
	ret = PCIBIOS_SUCCESSFUL;
out:
	spin_unlock_irqrestore(&wlock, flag);
	return ret;
}

static int32_t pcie_write_to_dbi(struct pcie_info *info,
	uint32_t devfn, int32_t where, int32_t size, uint32_t value)
{
	int32_t ret;
	unsigned long flag;
	uint32_t org;

	flag = 0;
	spin_lock_irqsave(&wlock, flag);

	if (pcie_read_from_dbi(info, devfn, where, PCIE_DATA_SIZE_4, &org)) {
		pr_info("Cannot read from dbi! 0x%x:0x%x:0x%x!\n", 0, devfn, where);
		ret = -EIO;
		goto out;
	}

	if (pcie_trans_write_data(where, size, value, &org)) {
		pr_info("Unknown size(%d) for read ops\n", size);
		ret = -1;
		goto out;
	}
	writel(org, (void *)(info->conf_base_addr + (where & (~PCIE_DBI_WHERE_MASK))));
	ret = PCIBIOS_SUCCESSFUL;
out:
	spin_unlock_irqrestore(&wlock, flag);
	return ret;
}

static int32_t pcie_write_conf(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t value)
{
	struct pcie_info *info = bus_to_info(bus->number);

	if (unlikely(info == NULL)) {
		pr_info("pcie write conf fail!\n");
		return -EIO;
	}

	if (bus->number == info->root_bus_nr)
		return pcie_write_to_dbi(info, devfn, where, size, value);

	return pcie_write_to_device(bus, devfn, where, size, value);
}

static int32_t pcie_multifunc_write_to_dbi(struct pcie_info *info,
	uint32_t devfn, int32_t where, int32_t size, uint32_t value)
{
	int32_t ret;
	unsigned long flag;
	uint32_t org;
	uint32_t cfg_shift_addr;

	/* domain:bus:dev(slot):fn, latter 2 form a devfn, only 1 dev is supported on 1 bus now */
	if (PCI_SLOT(devfn) > 0)
		return -EIO;

	flag = 0;
	spin_lock_irqsave(&wlock, flag);

	if (pcie_multifunc_read_from_dbi(info, devfn, where, PCIE_DATA_SIZE_4, &org)) {
		pr_info("Cannot read from dbi! 0x%x:0x%x:0x%x!\n", 0, devfn, where);
		ret = -EIO;
		goto out;
	}

	if (pcie_trans_write_data(where, size, value, &org)) {
		pr_info("Unknown size(%d) for read ops\n", size);
		ret = -EPERM;
		goto out;
	}

	cfg_shift_addr = PCIE_CFG_BUS(info->root_bus_nr) |
		PCIE_CFG_DEV(devfn) | PCIE_CFG_REG(where);
	writel(org, (void *)(info->conf_base_addr + cfg_shift_addr));
	ret = PCIBIOS_SUCCESSFUL;
out:
	spin_unlock_irqrestore(&wlock, flag);
	return ret;
}

static int32_t pcie_multifunc_write_conf(struct pci_bus *bus,
	uint32_t devfn, int32_t where, int32_t size, uint32_t value)
{
	struct pcie_info *info = bus_to_info(bus->number);

	if (unlikely(info == NULL)) {
		pr_info("pcie write conf fail!\n");
		return -EIO;
	}

	if (bus->number == info->root_bus_nr)
		return pcie_multifunc_write_to_dbi(info, devfn, where, size, value);

	return pcie_write_to_device(bus, devfn, where, size, value);
}

static void pcie_preinit(void)
{
	// pcie0
	MEM_SPACE_SET(0);
	// pcie1
	MEM_SPACE_SET(1);
	// pcie2
	MEM_SPACE_SET(2);
}

static uint8_t pci_common_swizzle_local(struct pci_dev *dev, u8 *pinp)
{
	uint8_t (*func_pci_common_swizzle)(struct pci_dev *dev, u8 *pinp) = NULL;

	func_pci_common_swizzle = (void *)hw_kallsyms_lookup_name("pci_common_swizzle");
	if (func_pci_common_swizzle == NULL) {
		pr_info("Can not find symbol pci_common_swizzle!\n");
		return -1;
	}

	return func_pci_common_swizzle(dev, pinp);
}

static int32_t check_resource_space(int index, struct pci_sys_data *sys,
	struct pcie_info *pcie_ctrl)
{
	int32_t ret;

	switch (index) {
	case 0:
		CHECK_RES_SPACE(0);
		if (ret)
			return ret;
		REQ_RES_CORRESPOND(0);
		break;
	case 1:
		CHECK_RES_SPACE(1);
		if (ret)
			return ret;
		REQ_RES_CORRESPOND(1);
		break;
	case 2:
		CHECK_RES_SPACE(2);
		if (ret)
			return ret;
		REQ_RES_CORRESPOND(2);
		break;
	default:
		break;
	}

	return 0;
}

static int32_t pcie_setup(int32_t nr, struct pci_sys_data *sys)
{
	int32_t ret;
	struct pcie_info *pcie_ctrl;
	struct pcie_info *info;

	if (nr >= pcie_controllers_nr)
		return 0;

	pcie_get_ctrl_info(&pcie_ctrl);
	info = &pcie_ctrl[nr];
	/* record busnr for cfg ops use */
	info->root_bus_nr = sys->busnr;
	sys->mem_offset = 0;

	/* requeset resources for corresponding controller */
	if (info->controller == PCIE_CTRL_TYPE_0) {
		ret = request_resource(&ioport_resource, &g_pcie0_io_space);
		if (ret) {
			pr_info("Cannot request io resource for pcie0, ret=%d\n", ret);
			/* 2125 LSW io space will alloc fail, function is still usable */
			if (pcie_is_extlsw_type2125(info->controller) != true)
				return ret;
		}
		ret = check_resource_space(0, sys, pcie_ctrl);
		if (ret)
			return ret;
	}

	if (info->controller == PCIE_CTRL_TYPE_1) {
		ret = request_resource(&ioport_resource, &g_pcie1_io_space);
		if (ret) {
			pr_info("Cannot requeset io resource for pcie1\n");
			return ret;
		}
		check_resource_space(1, sys, pcie_ctrl);
		if (ret)
			return ret;
	}

	if (info->controller == PCIE_CTRL_TYPE_2) {
		ret = request_resource(&ioport_resource, &g_pcie2_io_space);
		if (ret) {
			pr_info("Cannot requeset io resource for pcie2\n");
			return ret;
		}
		check_resource_space(2, sys, pcie_ctrl);
		if (ret)
			return ret;
	}

	return 1;
}

static int32_t pcie_scan_bus(int32_t nr, struct pci_host_bridge *bridge)
{
	int32_t ret;
	int32_t dev_nr;
	struct pcie_info *pcie_ctrl;
	struct pci_sys_data *sys = pci_host_bridge_priv(bridge);

	list_splice_init(&sys->resources, &bridge->windows);
	bridge->dev.parent = NULL;
	if ((nr < PCIE_INDEX_MAX) && (nr >= 0) && (g_plat_dev[nr] != NULL)) {
		ret = of_property_read_u32(g_plat_dev[nr]->dev.of_node, "nr", &dev_nr);
		if (ret != 0)
			pr_info("nr is missing a reg node, ret=%d\n", ret);

		if (nr == dev_nr)
			bridge->dev.parent = &(g_plat_dev[nr]->dev);
	}

	bridge->sysdata = sys;
	bridge->busnr = sys->busnr;
	if (pcie_get_interrupt_mode(nr) == PCIE_INTERRUPT_MODE_SMI)
		bridge->msi = hal_msi_get_msi_ctrl();

	pcie_ctrl = NULL;
	pcie_get_ctrl_info(&pcie_ctrl);
	if (nr < pcie_controllers_nr) {
		bridge->ops = &g_pcie_ops;
		ret = pci_scan_root_bus_bridge(bridge);
		if (ret < 0) {
			pcie_ctrl[nr].bridge = NULL;
			return ret;
		}
		pcie_ctrl[nr].bridge = bridge;
		return ret;
	}
	pr_info("Unknown controller nr :0x%x!\n", nr);
	return -ENODEV;
}

static int32_t pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
	uint32_t pcie_index;
	uint32_t loop;
	uint32_t pin_num;
	struct pcie_info *info;
	struct pcie_board_ini_attr *pcie_board_cfg;
	uint32_t chipid;
	uint32_t pcie0_irq_shift;
	struct pcie_pin_irq pcie_irq_handle[] = {
		{PCIE_INTA_PIN, {PCIE0_IRQ_INTA, PCIE1_IRQ_INTA, PCIE2_IRQ_INTA}},
		{PCIE_INTB_PIN, {PCIE0_IRQ_INTB, PCIE1_IRQ_INTB, PCIE2_IRQ_INTB}},
		{PCIE_INTC_PIN, {PCIE0_IRQ_INTC, PCIE1_IRQ_INTC, PCIE2_IRQ_INTC}},
		{PCIE_INTD_PIN, {PCIE0_IRQ_INTD, PCIE1_IRQ_INTD, PCIE2_IRQ_INTD}}
	};

	if ((pin < PCIE_INTA_PIN) || (pin > PCIE_INTD_PIN)) {
		pr_info("invalid irq, pin:0x%x\n", pin);
		return -1;
	}

	if (pcie_get_interrupt_mode(dev->bus->number) != PCIE_INTERRUPT_MODE_INTX) {
		pr_info("pcie not support INTx, please check ini config, controller %d!\n",
			dev->bus->number);
		return -EOPNOTSUPP;
	}

	info = bus_to_info(dev->bus->number);
	if (info == NULL) {
		pr_info("pcie map irq fail, controller %d!\n", dev->bus->number);
		return -1;
	}
	if (info->controller == PCIE_CTRL_TYPE_0) {
		pcie_index = PCIE_INDEX_0;
	} else if (info->controller == PCIE_CTRL_TYPE_1) {
		pcie_index = PCIE_INDEX_1;
	} else if (info->controller == PCIE_CTRL_TYPE_2) {
		pcie_index = PCIE_INDEX_2;
	} else {
		pr_info("pcie controller index is unknown!\n");
		return -1;
	}

	pcie_get_board_attr(&pcie_board_cfg);
	if (pcie_board_cfg == NULL) {
		pr_info("pcie board get attr error!\n");
		return -1;
	}

	chipid = pcie_get_chip_id();
	pcie0_irq_shift = 0;
	if ((chipid == HAL_CHIP_ID_1156H) || (chipid == HAL_CHIP_ID_1155H))
		pcie0_irq_shift = PICE0_IRQ_INT_SHIFT_1156;

	/* interrupt reporting processing */
	if (chipid == HAL_CHIP_ID_5182T) {
		/* INTX interrupt of the 82T is converged to the MSI for reporting. */
		return g_pcie_reg_base_addr[pcie_index].pcie_msi_irq_num + pin - PCIE_INTA_PIN;
	}

	pin_num = sizeof(pcie_irq_handle) / sizeof(struct pcie_pin_irq);
	for (loop = 0; loop < pin_num; loop++) {
		if (pin == pcie_irq_handle[loop].pcie_pin) {
			uint32_t res;

			res = pcie_irq_handle[loop].pcie_irq[pcie_index] - pcie0_irq_shift;
			pr_info("pcie irq pcie_index:%u pin:%u irq:%u\n",
				pcie_index, pin, res);
			/* interrupt ID provided for the SSD NVMe
			 * needs to be converted to the virtual interrupt ID
			 */
			if (pcie_index == pcie_board_cfg->ssd_pcie_channel) {
				hal_msi_get_irq_num(res, &res);
				pr_info("pcie ssd virq:%u\n", res);
			}
			return res;
		}
	}

	/* return failure if not found */
	pr_info("Unknown pin for mapping irq!\n");
	return -1;
}

void pcie_select(void)
{
	struct pcie_board_ini_attr *pcie_board_cfg = NULL;

	pcie_get_board_attr(&pcie_board_cfg);

	/* checck if pcie0 enabled */
	if ((pcie_board_cfg->pcie_channel_select & PCIE0_MODE_SEL) != 0)
		g_pcie0_sel = pcie0_x1_sel;

	/* checck if pcie1 enabled */
	if ((pcie_board_cfg->pcie_channel_select & PCIE1_MODE_SEL) != 0)
		g_pcie1_sel = pcie1_x1_sel;

	/* checck if pcie2 enabled */
	if ((pcie_board_cfg->pcie_channel_select & PCIE2_MODE_SEL) != 0)
		g_pcie2_sel = pcie2_x1_sel;
}

int32_t pcie_prepare_init_common_resource(void)
{
	uint32_t chip_id;
	uint32_t index;

	void *__iomem pcie_misc_base = NULL;

	/* virtual address for mapping PCIe promiscuous reg.
	 * This addr will be released when init fails
	 */
	for (index = 0; index < PCIE_INDEX_MAX; index++) {
		/* skip the space mapping operation when misc addr is not init */
		if (g_pcie_reg_base_addr[index].misc_base_addr == 0)
			continue;

		/* PCIe reg in the system controller are changed to the apb space of the PCIe
		 * ISO reg are still
		 */
		pcie_misc_base = ioremap(g_pcie_reg_base_addr[index].misc_base_addr,
			PCIE_MISC_BASE_SIZE);
		if (!pcie_misc_base) {
			pr_info("Cannot map system controller register base!\n");
			return -EIO;
		}
		pcie_set_misc_base_virt(index, pcie_misc_base);
	}

	g_sysctrl_base_virt = ioremap(PCIE_SYS_BASE_PHYS, PCIE_DBI_BASE_SIZE);
	if (!g_sysctrl_base_virt) {
		pr_info("Cannot map sysctrl register base!\n");
		return -EIO;
	}

	/* Enable PCIE power(pcie iso): 0x10100134 bit1=0 */
	chip_id = pcie_get_chip_id();
	if ((chip_id == HW_CHIP_ID_5116H_E) ||
		(chip_id == HW_CHIP_ID_5116T_E) ||
		(chip_id == HW_CHIP_ID_5116TV5_E))
		clear_reg_bit(g_sysctrl_base_virt + SC_PERCTRL38, 1);

	iounmap(g_sysctrl_base_virt);
	return 0;
}

#endif

void get_space_size(void)
{
	/* pcie0 resource distribution selection */
	SPACE_SIZE_SET(0);

	/* pcie1 resource distribution selection */
	SPACE_SIZE_SET(1);

	/* pcie2 resource distribution selection */
	/* pcie2 does not need to assign g_pcie_reg_base_addr value right now */
	SPACE_SIZE_SET(2);

	pr_info("g_pcie0_mem_space_size:%#x, g_pcie0_base_space_size:%#x\n",
		g_pcie0_mem_space_size, g_pcie0_base_space_size);
	pr_info("g_pcie1_mem_space_size:%#x, g_pcie1_base_space_size:%#x\n",
		g_pcie1_mem_space_size, g_pcie1_base_space_size);
	pr_info("g_pcie2_mem_space_size:%#x, g_pcie2_base_space_size:%#x\n",
		g_pcie2_mem_space_size, g_pcie2_base_space_size);
}

int32_t set_iatu_table(void)
{
	uint32_t chipid;
	uint32_t pcie0_len = 0;
	uint32_t pcie1_len = 0;
	uint32_t pcie2_len = 0;
	struct pcie_iatu *pcie0_iatu;
	struct pcie_iatu *pcie1_iatu;
	struct pcie_iatu *pcie2_iatu;

	pcie0_iatu = NULL;
	pcie1_iatu = NULL;
	pcie2_iatu = NULL;

	/* get soc id */
	chipid = pcie_get_chip_id();
	/* special process for 5182T iatu table */
	if (chipid == HAL_CHIP_ID_5182T) {
		pcie0_iatu = g_pcie0_iatu_table_5182t;
		pcie1_iatu = g_pcie1_iatu_table_5182t;
		pcie2_iatu = g_pcie2_iatu_table_5182t;
		pcie0_len = ARRAY_SIZE(g_pcie0_iatu_table_5182t);
		pcie1_len = ARRAY_SIZE(g_pcie1_iatu_table_5182t);
		pcie2_len = ARRAY_SIZE(g_pcie2_iatu_table_5182t);
		pcie_set_iatu_table(pcie0_iatu, pcie1_iatu, pcie2_iatu);
		pcie_set_iatu_table_len(pcie0_len, pcie1_len, pcie2_len);
		return 0;
	}

	if ((chipid == HAL_CHIP_ID_1156H) || (chipid == HAL_CHIP_ID_1156H)) {
		pcie0_iatu = g_pcie0_iatu_table_1156;
		pcie0_len = ARRAY_SIZE(g_pcie0_iatu_table_1156);
		pcie_set_iatu_table(pcie0_iatu, pcie1_iatu, pcie2_iatu);
		pcie_set_iatu_table_len(pcie0_len, pcie1_len, pcie2_len);
		return 0;
	}

	/* pcie0 iatu table select */
	if (pcie_is_wifi115x_chip(PCIE_INDEX_0)) {
		pcie0_iatu = g_pcie0_iatu_table_1152;
		pcie0_len = ARRAY_SIZE(g_pcie0_iatu_table_1152);
	} else if (pcie_is_extlsw_type2125(PCIE_INDEX_0)) {
		pcie0_iatu = g_pcie0_iatu_table_extlsw_type2125;
		pcie0_len = ARRAY_SIZE(g_pcie0_iatu_table_extlsw_type2125);
	} else {
		pcie0_iatu = g_pcie0_iatu_table_common;
		pcie0_len = ARRAY_SIZE(g_pcie0_iatu_table_common);
	}

	/* pcie1 iatu table select */
	if (pcie_is_wifi115x_chip(PCIE_INDEX_1)) {
		pcie1_iatu = g_pcie1_iatu_table_1152;
		pcie1_len = ARRAY_SIZE(g_pcie1_iatu_table_1152);
	} else {
		pcie1_iatu = g_pcie1_iatu_table_common;
		pcie1_len = ARRAY_SIZE(g_pcie1_iatu_table_common);
	}

	pcie_set_iatu_table(pcie0_iatu, pcie1_iatu, pcie2_iatu);
	pcie_set_iatu_table_len(pcie0_len, pcie1_len, pcie2_len);
	return 0;
}

static int32_t pcie_sys_init_5115(uint32_t mode_sel)
{
	uint32_t ret;
	struct pcie_link_ops_reg link_ops_reg;

	link_ops_reg.is_5115_type = true;
	/* dbi base addr */
	link_ops_reg.dbi_base_addr[PCIE_INDEX_0] = DBI_BASE_ADDR_0;
	link_ops_reg.dbi_base_addr[PCIE_INDEX_1] = DBI_BASE_ADDR_1;
	/* pcie controller reg */
	link_ops_reg.ctrl_reg_0[PCIE_INDEX_0] = PERI_PCIE0_5115;
	link_ops_reg.ctrl_reg_0[PCIE_INDEX_1] = PERI_PCIE1_0;
	link_ops_reg.ctrl_reg_1[PCIE_INDEX_0] = PERI_PCIE1_5115;
	link_ops_reg.ctrl_reg_1[PCIE_INDEX_1] = PERI_PCIE1_1;
	link_ops_reg.ctrl_reg_6[PCIE_INDEX_0] = PERI_PCIE6_5115;
	link_ops_reg.ctrl_reg_6[PCIE_INDEX_1] = PERI_PCIE1_6;
	link_ops_reg.ctrl_reg_7[PCIE_INDEX_0] = PERI_PCIE7_5115;
	link_ops_reg.ctrl_reg_7[PCIE_INDEX_1] = PERI_PCIE1_7;
	link_ops_reg.ctrl_reg_8[PCIE_INDEX_0] = PERI_PCIE8_5115;
	link_ops_reg.ctrl_reg_8[PCIE_INDEX_1] = PERI_PCIE1_8;
	link_ops_reg.ctrl_reg_9[PCIE_INDEX_0] = PERI_PCIE9_5115;
	link_ops_reg.ctrl_reg_9[PCIE_INDEX_1] = PERI_PCIE1_9;
	/* pcie link status reg, old chips do not support 2.0 except 5610T */
	link_ops_reg.link_state_reg[PCIE_INDEX_0] = PCIE0_LINK_STAT_5115;
	link_ops_reg.link_state_reg[PCIE_INDEX_1] = PCIE1_LINK_STAT_5115;
	link_ops_reg.link_2d0_reg[PCIE_INDEX_0] = PCIE0_2D0_LINK_STAT_5115;
	link_ops_reg.link_2d0_reg[PCIE_INDEX_1] = PCIE1_2D0_LINK_STAT_5115;

	if ((mode_sel & PCIE0_MODE_SEL) == PCIE0_MODE_SEL)
		ret = pcie_hisi_sys_init(PCIE_INDEX_0, link_ops_reg);
	if ((mode_sel & PCIE1_MODE_SEL) == PCIE1_MODE_SEL)
		ret = pcie_hisi_sys_init(PCIE_INDEX_1, link_ops_reg);

	return 0;
}

static int32_t pcie_sys_init_common(uint32_t mode_sel)
{
	uint32_t index;
	struct pcie_link_ops_reg link_ops_reg;
	uint32_t ret = 0;

	void *__iomem pcie_misc_base;

	feature_issupport_funcptr *feature_issupport = get_feature_issupport_func_hook();

	if ((feature_issupport == NULL) || (*feature_issupport == NULL))
		return false;

	/* check feature switch to determine if init as PCIe1.0 mode */
	if (((*feature_issupport)("HW_FT_AMP_HAVE_PCIE_SWITCH") == 1) &&
		((*feature_issupport)("HW_FT_AMP_PCIE0_FORCE_PCIE10") == 1) &&
		((*feature_issupport)("HW_FT_AMP_PCIE1_FORCE_PCIE10") == 1))
		pcie_bridge_config_pcie10();

	link_ops_reg.is_5115_type = false;

	for (index = 0; index < PCIE_INDEX_MAX; index++) {
		/* if pcie control channel disabled, skip init */
		if ((mode_sel & (1 << index)) != (1 << index))
			continue;

		/* dbi base addr */
		link_ops_reg.dbi_base_addr[index] = g_pcie_reg_base_addr[index].dbi_base_addr;
		/* pcie controller reg */
		link_ops_reg.ctrl_reg_0[index] = PERI_PCIE0_5116;
		link_ops_reg.ctrl_reg_1[index] = PERI_PCIE1_5116;
		link_ops_reg.ctrl_reg_6[index] = PERI_PCIE6_5116;
		link_ops_reg.ctrl_reg_7[index] = PERI_PCIE7_5116;
		link_ops_reg.ctrl_reg_8[index] = PERI_PCIE8_5116;
		link_ops_reg.ctrl_reg_9[index] = PERI_PCIE9_5116;
		/* pcie link status reg */
		link_ops_reg.link_state_reg[index] = g_pcie_reg_base_addr[index].link_status_reg;
		link_ops_reg.link_2d0_reg[index] = g_pcie_reg_base_addr[index].link_2d0_status_reg;
		ret = pcie_hisi_sys_init(index, link_ops_reg);
		if (ret != 0)
			continue;

		pcie_misc_base = NULL;
		/* PCIe link down auto reset enable, 14bit 0 to close auto reset, 1 to open */
		pcie_get_misc_base_virt(index, &pcie_misc_base);
		set_reg_bit(pcie_misc_base + PERI_PCIE11_5116, PCIE_BIT_14);
		set_reg_bit(pcie_misc_base + PERI_PCIE12_5116, PCIE_BIT_21);
	}
	return 0;
}

static int32_t pcie_sys_init(void)
{
	int32_t ret;
	bool is_old_soc;
	struct pcie_board_ini_attr *pcie_board_cfg;

	ret = pcie_is_5115_chip(&is_old_soc);
	if (ret != 0)
		return ret;

	pcie_get_board_attr(&pcie_board_cfg);
	if (is_old_soc == true)
		return pcie_sys_init_5115(pcie_board_cfg->pcie_channel_select);
	else
		return pcie_sys_init_common(pcie_board_cfg->pcie_channel_select);
}

static void pci_common_init_local(struct hw_pci *hw)
{
	void (*func_pci_common_init)(struct device *, struct hw_pci *hw) = NULL;

	func_pci_common_init = (void *)hw_kallsyms_lookup_name("pci_common_init_dev");
	if (func_pci_common_init == NULL) {
		pr_info("Can not find symbol pci_common_init!\n");
		return;
	}

	return func_pci_common_init(&(g_plat_dev[0]->dev), hw);
}

/* for old chips */
int32_t pcie_init_5115(void)
{
	uint32_t cfg_size;
	uint32_t mem_size;
	uint32_t loop;
	int32_t ret;
	uint32_t chip_id;

	void *__iomem pcie_misc_base = NULL;

	chip_id = pcie_get_chip_id();
	pr_info("pcie0 sel: 0x%x, pcie1 sel:0x%x,pcie0 memsize:0x%x, pcie1 memsize:0x%x.\n",
			g_pcie0_sel, g_pcie1_sel, g_pcie0_mem_space_size, g_pcie1_mem_space_size);
	/* maybe IO_ADDRESS is better */
	pcie_misc_base = ioremap(PCIE_SYS_BASE_PHYS, PCIE_OLD_MISC_BASE_SIZE);
	if (!pcie_misc_base) {
		pr_info("Cannot map system controller register base!\n");
		return -EIO;
	}
	pcie_set_misc_base_virt(PCIE_INDEX_0, pcie_misc_base);
	pcie_set_misc_base_virt(PCIE_INDEX_1, pcie_misc_base);

	pcie_undo_reset(true);

	ret = pcie_sys_init();
	if (ret != 0)
		return -EIO;

	/* if enabled pcie0 */
	cfg_size = PCIE_OLD_BASE_CFG_SIZE;
	mem_size = PCIE_OLD_MEM_SIZE;
	for (loop = PCIE_INDEX_0; loop < PCIE_INDEX_MAX; loop++) {
		ret = pcie_ctrl_init(loop, cfg_size, mem_size, &pcie_controllers_nr);
		if (ret != HW_RET_SUCCESS)
			return ret;
	}
	/* none of the two controllers work at rc mode or is enabled, we do nothing */
	if (!pcie_controllers_nr) {
		pr_info("None of the two pcie controllers is enabled!\n");
		return -EIO;
	}
	/* reset how many controllers to enable. */
	g_sd511x_pcie.nr_controllers = pcie_controllers_nr;
	pci_common_init_local(&g_sd511x_pcie);
	return 0;
}

static void pcie_set_private_data(struct hw_pci *pci)
{
	struct pcie_board_ini_attr *pcie_board_cfg = NULL;

	pcie_get_board_attr(&pcie_board_cfg);
	/* pcie controller cross process */
	if (pcie_board_cfg->pcie_channel_cross == PCIE_CTRL_CHANNEL_CROSS_ON) {
		g_dbi_base_addr[PCIE_INDEX_0][0] = pcie_get_dbi_addr(PCIE_INDEX_1);
		g_dbi_base_addr[PCIE_INDEX_1][0] = pcie_get_dbi_addr(PCIE_INDEX_0);
	} else {
		g_dbi_base_addr[PCIE_INDEX_0][0] = pcie_get_dbi_addr(PCIE_INDEX_0);
		g_dbi_base_addr[PCIE_INDEX_1][0] = pcie_get_dbi_addr(PCIE_INDEX_1);
	}

	g_pci_private_data[PCIE_INDEX_0] = g_dbi_base_addr[PCIE_INDEX_0];
	g_pci_private_data[PCIE_INDEX_1] = g_dbi_base_addr[PCIE_INDEX_1];

	pci->private_data = (void **)&g_pci_private_data;
}

void pcie_msi_init(struct pcie_board_ini_attr *pcie_board_cfg)
{
	uint32_t i;

	for (i = 0; i < pcie_controllers_nr; i++) {
		struct pcie_info *cur_info;
		uint32_t pcie_index;

		cur_info = get_pcie_info_by_index(i);
		if (cur_info == NULL) {
			pr_info("get pcie info err, i=%d\n", i);
			continue;
		}

		/* controller id is the same as pcie index,
		 * controller id is used to indicate pcie index
		 */
		pcie_index = cur_info->controller - 1;
		if (pcie_get_interrupt_mode(pcie_index) != PCIE_INTERRUPT_MODE_SMI) {
			/* non-MSI mode, return directly */
			continue;
		}

		cur_info->hardware_irq = g_pcie_reg_base_addr[pcie_index].pcie_msi_irq_num;
		hal_pcie_init_msi_irq(cur_info);

		/* support PCIE msi enhance feature, create proc operation interface */
		pcie_msi_create_enhance_proc();
	}
}

int32_t pcie_init_common(void)
{
	uint32_t cfg_size;
	uint32_t mem_size;
	int32_t ret;
	uint32_t loop;
	struct pcie_board_ini_attr *pcie_board_cfg;
	pcie_test_funcptr *pcie_test = get_pcie_test_func_hook();

	pr_info("pcie0 sel: 0x%x, pcie1 sel:0x%x,pcie0 memsize:0x%x, pcie1 memsize:0x%x.\n",
		g_pcie0_sel, g_pcie1_sel, g_pcie0_mem_space_size, g_pcie1_mem_space_size);
	/* PCIe reg in the system controller are changed to
	 * the apb space of the PCIe, ISO reg are still here
	 */
	ret = pcie_prepare_init_common_resource();
	if (ret != 0)
		return -EIO;

	/* pcie reset and de-reset */
	pcie_undo_reset(true);
	ret = pcie_sys_init();
	if (ret != 0)
		return -EIO;

	pcie_board_cfg = NULL;
	pcie_get_board_attr(&pcie_board_cfg);
	for (loop = PCIE_INDEX_0; loop < PCIE_INDEX_MAX; loop++) {
		uint32_t pcie_index = loop;

		/* pcie controller cross process */
		if (pcie_board_cfg->pcie_channel_cross == PCIE_CTRL_CHANNEL_CROSS_ON)
			pcie_index = PCIE_INDEX_MAX - 1 - loop;

		cfg_size = g_pcie_reg_base_addr[pcie_index].cfg_base_size;
		mem_size = g_pcie_reg_base_addr[pcie_index].mem_base_size;
		ret = pcie_ctrl_init(pcie_index, cfg_size, mem_size, &pcie_controllers_nr);
		if (ret != HW_RET_SUCCESS)
			return ret;
	}

	/* none of the two controllers work at rc mode or is enabled, we do nothing */
	if (!pcie_controllers_nr) {
		pr_info("None of the two pcie controllers is enabled!\n");
		return 0;
	}

	/* MSI Interrupt Mechanism init */
	pcie_msi_init(pcie_board_cfg);

	/* reset how many controllers to enable. */
	g_sd511x_pcie.nr_controllers = pcie_controllers_nr;
	pcie_set_private_data(&g_sd511x_pcie);
	pci_common_init_local(&g_sd511x_pcie);

	if (pcie_test != NULL)
		*pcie_test = pcie_loopback_test;

	return 0;
}

uint32_t hisi_pcie_init(void)
{
	int32_t ret;
	bool is_old_soc;

	ret = pcie_is_5115_chip(&is_old_soc);
	if (ret != 0)
		return ret;

	/* pcie enable count */
	pcie_select();

	if (is_old_soc == true)
		return pcie_init_5115();
	else
		return pcie_init_common();
}

static void pcie_func_registration(void)
{
	close_pcie_funcptr *close_pcie = get_close_pcie_func_hook();

	// init pcie space read/write hook function
	if (pcie_is_extlsw_chip(PCIE_INDEX_0)) {
		g_pcie_ops.read = pcie_multifunc_read_conf;
		g_pcie_ops.write = pcie_multifunc_write_conf;
	} else {
		g_pcie_ops.read = pcie_read_conf;
		g_pcie_ops.write = pcie_write_conf;
	}

	// init pcie hook function
	g_sd511x_pcie.nr_controllers = PCIE_INDEX_MAX; /* default 2 controllers */
	g_sd511x_pcie.preinit = pcie_preinit;
	g_sd511x_pcie.swizzle = pci_common_swizzle_local;  // pci_std_swizzle
	g_sd511x_pcie.setup = pcie_setup;
	g_sd511x_pcie.scan = pcie_scan_bus;
	g_sd511x_pcie.map_irq = pcie_map_irq;
	if (close_pcie != NULL)
		*close_pcie = pcie_dev_force_close;
}

int32_t pcie3_lane_init_5182T(uint32_t pcie_mode_1, uint32_t pcie_mode_2, uint32_t value)
{
	int32_t ret;
	serdes_lane_init_funcptr *serdes_lane_init = get_serdes_lane_init_func_hook();

	if (serdes_lane_init == NULL)
		return -EIO;

	/* pcie lane init, 24 indicates pcie port num in sdk */
	(*serdes_lane_init)(0, (1 << 24), 0, pcie_mode_1);
	if (value != PCIE_X1_XFI_MODE)
		(*serdes_lane_init)(0, (1 << 24), 1, pcie_mode_2);

	/* PCIE3 channel mode cfg */
	ret = write_reg_iomap_value(PCIE3_MODE_REG_5182T, value);
	if (ret != HW_RET_SUCCESS)
		return -EIO;

	pr_info("pcie lane mode: %u init success!\n", value);
	pr_info("0:pcie_x2; 1:double pcie_x1; 10: pcie_x1_xfi;\n");

	return ret;
}

int32_t pcie_init_5182T(void)
{
	int32_t ret;
	struct pcie_board_ini_attr *pcie_board_cfg = NULL;

	g_pcie_reg_base_addr = g_pcie_reg_base_addr_5182t;

	/* clk enable */
	pcie_enable_clk(PCIE_INDEX_2);

	/* get cfg */
	pcie_get_board_attr(&pcie_board_cfg);

	ret = HW_RET_SUCCESS;
	if (pcie_board_cfg->pcie_lane_init_mode == PCIE_X2_MODE) {
		ret = pcie3_lane_init_5182T(HI_SERDES_PCIE2_x2, HI_SERDES_PCIE3_x2, PCIE_X2_MODE);
		if (ret != HW_RET_SUCCESS)
			return -EIO;
	} else if (pcie_board_cfg->pcie_lane_init_mode == PCIE_DOUBLE_X1_MODE) {
		ret = pcie3_lane_init_5182T(HI_SERDES_PCIE2, HI_SERDES_PCIE3, PCIE_DOUBLE_X1_MODE);
		if (ret != HW_RET_SUCCESS)
			return -EIO;
	} else if (pcie_board_cfg->pcie_lane_init_mode == PCIE_X1_XFI_MODE) {
		ret = pcie3_lane_init_5182T(HI_SERDES_PCIE3_1CS, HI_SERDES_PCIE3, PCIE_X1_XFI_MODE);
		if (ret != HW_RET_SUCCESS)
			return -EIO;
	}

	return ret;
}

void pcie_completa_enable_bdi_access(void)
{
	uint32_t i;
	struct pcie_board_ini_attr *pcie_board_cfg = NULL;
	struct pcie_info *pcie_ctrl = NULL;

	if (pcie_get_chip_id() != HW_CHIP_ID_5117V_E)
		return;

	pcie_get_board_attr(&pcie_board_cfg);
	if (pcie_board_cfg == NULL)
		return;

	pcie_get_ctrl_info(&pcie_ctrl);
	if (pcie_ctrl == NULL)
		return;

	for (i = 0; i < PCIE_INDEX_MAX; i++) {
		if ((pcie_board_cfg->chan_attr[i].wifi_chip_type == WIFI_CHIP_TYPE_1153) &&
		    ((pcie_board_cfg->pcie_channel_select & (1 << i)) != 0) &&
			(pcie_ctrl[i].misc_base != NULL)) {
			set_reg_bit(pcie_ctrl[i].misc_base + PERI_PCIE7_5116, PCIE_BIT_13);
		}
	}
}

static int32_t __init pcie_init(void)
{
	int32_t ret;
	uint32_t chipid;

	ret = platform_driver_register(&pcie_driver);
	pr_info("\n signal_platform_driver_register pcie reason = %d\n", ret);

	/* get soc id */
	chipid = pcie_get_chip_id();
	if (chipid == HW_CHIP_ID_5116T_E)
		disable_l2cache_outer();

	/* enable pcie clk */
	pr_info("PCIE clk enable configure:\n");
	pcie_enable_clk(PCIE_INDEX_0);
	if ((chipid != HAL_CHIP_ID_1156H) && (chipid != HAL_CHIP_ID_1155H) &&
		(chipid != HAL_CHIP_ID_1156E) && (chipid != HAL_CHIP_ID_2952H))
		pcie_enable_clk(PCIE_INDEX_1);  /* 1156 only support 1 PCIE */

	ret = pcie_board_parse_ini_cfg();
	if (ret != HW_RET_SUCCESS)
		return -EIO;

	/* special process for 82T: pcie cfg changed, enable pcie2 clk, PCIE3.0 mode cfg */
	if (chipid == HAL_CHIP_ID_5182T) {
		ret = pcie_init_5182T();
		if (ret != HW_RET_SUCCESS)
			return -EIO;
	} else if ((chipid == HAL_CHIP_ID_1156H) || (chipid == HAL_CHIP_ID_1156E) ||
		   (chipid == HAL_CHIP_ID_2952H)) {
		g_pcie_reg_base_addr = g_pcie_reg_base_addr_1156;
	} else if (chipid == HAL_CHIP_ID_1155H) {
		g_pcie_reg_base_addr = g_pcie_reg_base_addr_1155;
	}

	/* pcie hook func registration */
	pcie_func_registration();

	/* get mem, io space size */
	get_space_size();

	/* get iatu table cfg */
	ret = set_iatu_table();
	if (ret != 0)
		return -EIO;

	/* hisi pcie init */
	ret = hisi_pcie_init();
	pcie_undo_ioremap();

	pcie_aging_loopback_test(chipid);
	set_pcie_link_speed_info_func_hook(pcie_chip_link_speed_info_get);

	pcie_completa_enable_bdi_access();
	return ret;
}
module_init(pcie_init);

static void __exit pcie_exit(void)
{
	uint32_t i;
	struct pcie_info *pcie_ctrl;
	close_pcie_funcptr *close_pcie;
	pcie_test_funcptr *pcie_test;

	close_pcie = get_close_pcie_func_hook();
	if (close_pcie != NULL)
		*close_pcie = NULL;

	pcie_test = get_pcie_test_func_hook();
	if (pcie_test != NULL)
		*pcie_test = NULL;

	pcie_ctrl = NULL;
	pcie_get_ctrl_info(&pcie_ctrl);

	for (i = PCIE_INDEX_0; i < PCIE_INDEX_MAX; i++) {
		if (pcie_ctrl[i].bridge != NULL)
			if (pcie_ctrl[i].bridge->bus != NULL)
				pci_remove_root_bus(pcie_ctrl[i].bridge->bus);

		iounmap((void *)pcie_ctrl[i].conf_base_addr);
		iounmap((void *)pcie_ctrl[i].base_addr);
		iounmap((void *)pcie_ctrl[i].dbi_base);
		iounmap((void *)pcie_ctrl[i].misc_base);
	}

	if (pcie_ctrl[PCIE_INDEX_2].is_req_resource) {
		release_resource(&g_pcie2_mem_space);
		release_resource(&g_pcie2_io_space);
	}

	if (pcie_ctrl[PCIE_INDEX_1].is_req_resource) {
		release_resource(&g_pcie1_mem_space);
		release_resource(&g_pcie1_io_space);
	}

	if (pcie_ctrl[PCIE_INDEX_0].is_req_resource) {
		release_resource(&g_pcie0_mem_space);
		release_resource(&g_pcie0_io_space);
	}

	pcie_undo_reset(false);
	pcie_clk_power_exit();
	platform_driver_unregister(&pcie_driver);
}
module_exit(pcie_exit);

MODULE_LICENSE("GPL v2");
